// * FormItem组件
<template>
  <div class="s-form-item">
    <label
      :class="{
        's-form-item-label-required': isRequired && !isHideRequiredMark,
      }"
      v-if="label"
      >{{ label }}</label
    >
    <div>
      <slot></slot>
      <div
        class="s-form-item-error-messge"
        v-if="validateState === validateStateEnums.ERROR"
      >
        {{ validateMsg }}
      </div>
    </div>
  </div>
</template>

<script>
import Emitter from '../../mixins/emitter'
import AsyncValidator from 'async-validator'
import { validateStateEnums } from './enums'
import { deepClone } from '../../utils/assist'

export default {
  name: 'FormItem',

  inject: ['form'],

  components: {},

  mixins: [Emitter],

  props: {
    label: {
      type: String,
    },
    prop: {
      type: String,
    },
  },

  data() {
    return {
      validateStateEnums: validateStateEnums, // 校验状态枚举
      validateState: validateStateEnums.UNVALIDATE, // 校验状态

      // 校验信息
      validateMsg: '',

      initialValue: '', // 初始值
      isRequired: false, // 是否时必填项
    }
  },

  computed: {
    fieldValue() {
      return this.form.model[this.prop]
    },
    fieldRules() {
      return this.form.rules[this.prop] || []
    },
    isHideRequiredMark() {
      return this.form.hideRequiredMark
    },
  },

  watch: {},

  created() {},

  mounted() {
    // 只有prop存在时，才需要验证
    if (this.prop) {
      // 通知form组件对formItem添加or删除
      this.dispatch('Form', 'on-form-item-add', this)
      this.$on('hook:beforeDestroy', () => {
        this.dispatch('Form', 'on-form-item-remove', this)
      })

      this.initialValue = deepClone(this.fieldValue)
      // 监听表单事件
      this.setRules()
    }
  },

  methods: {
    // * 设置验证
    setRules() {
      this.isRequired = !!this.fieldRules.some(rule => rule.required === true)

      this.$on('on-form-change', this.onFieldChange)
      this.$on('on-form-blur', this.onFieldBlur)
    },

    // * 验证
    validate(trigger, callback) {
      const rules = getRulesByTrigger.call(this)
      const value = this.fieldValue

      // 没有匹配的rule，则无需验证
      if (rules.length <= 0) {
        return Promise.reject(new Error('no need to validate'))
      }

      this.validateState = validateStateEnums.VALIDATING

      return validateField.call(this)

      // 验证字段
      function validateField() {
        const descriptor = { [this.prop]: rules }
        const data = { [this.prop]: value }

        const validator = new AsyncValidator(descriptor)
        return validator
          .validate(data, { firstFields: true, suppressWarning: true })
          .then(() => {
            this.validateState = validateStateEnums.SUCCESS
            this.validateMsg = ''

            if (callback) callback(this.validateState)
            else return true
          })
          .catch(({ errors, fields }) => {
            this.validateState = validateStateEnums.ERROR
            this.validateMsg = errors[0].message

            if (callback) callback(this.validateState, this.validateMsg)
            else throw new Error(this.validateMsg)
          })
      }

      // 获取指定trigger的rules
      function getRulesByTrigger() {
        let result
        try {
          result = this.fieldRules.filter(
            rule =>
              rule.trigger.toLowerCase().indexOf(trigger.toLowerCase()) !== -1
          )
        } catch (err) {
          result = []
        }
        return result
      }
    },

    resetField() {
      this.validateState = validateStateEnums.UNVALIDATE
      this.validateMsg = ''
      this.form.model[this.prop] = this.initialValue
    },

    // * 设置验证（input时触发）
    onFieldChange() {
      this.validate('change').catch(() => {})
    },
    // * 设置验证（blur时触发）
    onFieldBlur() {
      this.validate('blur').catch(() => {})
    },
  },
}
</script>

<style lang="scss" scoped>
.s-form-item {
  .s-form-item-label-required {
    &::before {
      content: '*';
      color: red;
    }
  }

  .s-form-item-error-messge {
    color: red;
  }
}
</style>
